package cc.autoapi.pucong.auto.flow.persistence.utils;


import com.alibaba.fastjson2.JSON;
import cc.autoapi.pucong.auto.flow.core.root.utils.SystemConstant;
import cc.autoapi.pucong.auto.flow.persistence.bo.jwt.CheckResult;
import cc.autoapi.pucong.auto.flow.persistence.bo.jwt.Claims;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.text.ParseException;
import java.util.Date;
import java.util.UUID;

/**
 * @author : zy
 * JWT工具类
 */
@Slf4j
public class JwtUtils {

    //密钥
    private static final String secret = "a111aanl5ksinxkqaaa6vcx3zaq1wsxvv";

    // 1000 * 60 * 60 * 24 * 1  一天
    //过期时间12h，单位毫秒
    private static final long EXPIRE = 1000 * 60 * 60 * 12;

    /**
     * 创建token
     *
     * @param claims 用户信息
     * @return 令牌
     */
    public static String createToken(Claims claims) {
        try {
            //对密钥进行签名
            JWSSigner jwsSigner = new MACSigner(secret);

            //准备JWS header
            JWSHeader jwsHeader = new JWSHeader
                    .Builder(JWSAlgorithm.HS256)
                    .type(JOSEObjectType.JWT)
                    .build();

            //准备JWS payload
            claims.setJti(UUID.randomUUID().toString());
            claims.setIat(new Date().getTime());
            claims.setExp(new Date(System.currentTimeMillis() + EXPIRE).getTime());

            Payload payload = new Payload(JSON.toJSONString(claims));

            //封装JWS对象
            JWSObject jwsObject = new JWSObject(jwsHeader, payload);

            //签名
            jwsObject.sign(jwsSigner);

            return jwsObject.serialize();

        } catch (KeyLengthException e) {
            e.printStackTrace();
        } catch (JOSEException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String autoRefreshToken(CheckResult checkResult, String lsso_token) {
        String refreshToken = lsso_token;
        Claims claims = checkResult.getClaims();
        if (claims.getExp() > new Date().getTime()) {
            refreshToken = refreshToken(lsso_token);
        }
        return refreshToken;
    }

    private static String refreshToken(String token) {
        CheckResult checkResult = JwtUtils.verifyToken(token);
        if (checkResult.isSuccess()) {
            Claims claims = checkResult.getClaims();
            String newToken = JwtUtils.createToken(claims);
            return newToken;
        } else {
            return checkResult.getErrCode();
        }
    }

    /**
     * 验证并获取用户信息
     *
     * @param token 令牌
     * @return 解析后用户信息
     */
    public static CheckResult verifyToken(String token) {
        CheckResult checkResult = new CheckResult();
        JWSObject jwsObject;
        try {
            jwsObject = JWSObject.parse(token);

            //HMAC验证器
            JWSVerifier jwsVerifier = new MACVerifier(secret);
            if (!jwsObject.verify(jwsVerifier)) {
                checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
                checkResult.setSuccess(false);
                return checkResult;
            }

            String payload = jwsObject.getPayload().toString();
            Claims claims = JSON.parseObject(payload, Claims.class);
            if (claims.getExp() < new Date().getTime()) {
                checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
                checkResult.setSuccess(false);
                return checkResult;
            }
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
            return checkResult;
        } catch (ParseException | JOSEException e) {
            log.error("获取jwt失败", e);
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    /**
     * 获取请求中的token
     *
     * @return
     */
    public static String getToken() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //从cookie中获取token
        String lsso_token = null;
        Cookie[] cookieArr = request.getCookies();
        if (cookieArr != null && cookieArr.length > 0) {
            for (Cookie cookie : cookieArr) {
                if (SystemConstant.JWT_TOKEN.equals(cookie.getName())) {
                    lsso_token = cookie.getValue();
                }
            }
        }
        // 没有则从header中拿token,方便swagger调试
        if (StringUtils.isBlank(lsso_token)) {
            lsso_token = request.getHeader(SystemConstant.JWT_TOKEN);
        }
        return lsso_token;
    }
}